This notebook is Part 2 of “Introductory Big Data Analyses to gain insights in Precision Medicine” course.

R setup | Install software

R setup | Packages

install.packages('dplyr', depencies=TRUE)
library(dplyr)

Download data and open file in R

  1. Download data from exorbase website.

  2. Open file in R

hcc_rna<-read.delim(file.choose(),header=TRUE)

Other functions to open file

R packages for Data wrangling

Reference: Grolemund, G., & Wickham, H. (2017). R for Data Science. O’Reilly Media.


Step 1 Data wrangling using dplyr packages

1. Load dplyr package

library(dplyr)

2. Filter rows

# filter ( data frame, column name == value) 
# can use <, <=, >, >=
FGR_expression<-filter(hcc_rna, Gene.symbol=="FGR")
hcc004_expression<-filter(hcc_rna, HCC004<=1)

#if you have multiple criteria
# can use | (or), & (and)
hcc004_hcc002_expression<-filter(hcc_rna, HCC004<=1 & HCC002>1)

Reference: https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf

3. Arrange rows

# arrange (data frame, column name)
hcc_sort<-arrange(hcc_rna, Gene.symbol)

#sort by more than one variable
hcc_sort<-arrange(hcc_rna, HCC001,Gene.symbol)

4. Select columns

# select (data frame, column name 1, column name 2)
hcc_select<-select(hcc_rna, Gene.symbol, HCC004)

5. Select all columns except specific column

# select (data frame, -columns that you don't want)
hcc_all<-select(hcc_rna, -c(Gene.symbol, HCC004))

6. Recode data

eg. Calculate how many patients that have RNA expression >0 and store this value in a new column called “counthighexp”
# mutate (data frame, new column name = functions)
hcc_highexp<-mutate(hcc_rna,counthighexp=rowSums(hcc_rna>0))
eg. Recode numeric values to categories
# mutate (data frame, new column name = functions)
hcc_highexp <-mutate(hcc_highexp, cat = case_when(
                         counthighexp < 50 ~ "low",
                         counthighexp >= 50 ~ "high"))

7. Summarize data

summarize(hcc_highexp,mean(counthighexp))

8. Handle relational data (Multiple tables of data)

Reference: Grolemund, G., & Wickham, H. (2017). R for Data Science. O’Reilly Media.

# inner_join (data frame 1, data frame 2, by="key")
hcc_healthy<-inner_join(hcc_rna,healthy_rna, by="Gene.symbol")

Exercise 1

  1. Generate a mastersheet by merging hcc_rna dataset and healthy_rna dataset. Name the new mastersheet as hcc_healthy.

    Question: What type of join will you use for this dataset?
  2. Summarize number of genes from hcc_healthy.

  3. In hcc_healthy, use Gene.symbol column as row names of the table.

#without any package: data.frame(dataset name, row.names = column number)
#using tidyverse package: column_to_rownames(dataset name , var="key") 
  1. Then, remove genes that have 0 expression in 90% of samples in the dataset. Name the dataset as hcc_healthy_highexp
  2. Summarize the number of genes that have expression value >0 in 90% of the samples.
  3. Normalize all gene expressions using the log2 transformation. Name the dataset as hcc_healthy_log
#log((data frame+1),2)

Exercise 1 answers

#merge hcc_rna with healthy_rna
hcc_healthy<-full_join(hcc_rna,healthy_rna)
#35517 genes

#convert gene symbol column to rownames
hcc_healthy <- data.frame(hcc_healthy, row.names = 1)

#remove genes that has 0 expression in 90% of samples in both datasets
hcc_healthy<-mutate(hcc_healthy,count0=rowSums(hcc_healthy<=0))
hcc_healthy_highexp<-filter(hcc_healthy,count0<=207)
hcc_healthy_highexp<-select(hcc_healthy_highexp,-count0)
#18,575 genes left

#log transformation of the data
hcc_healthy_log<-log((hcc_healthy_highexp+1),2)

About Data normalization


Step 3a Data visualization (Basic histogram)

R packages for data visualizations

#Install packages
install.packages("ggplot2",dependencies=TRUE)
install.packages("ggpubr",dependencies=TRUE)

#Load packages
library(ggplot2)
library(ggpubr)

Reference: https://rstudio.github.io/cheatsheets/data-visualization.pdf

Let’s visualize the the dataset before and after normalization

  1. Transpose the dataset
#Transpose the datasets so that the RNA names are in columns while samples are in rows
raw_trans<-data.frame(t(hcc_healthy))
normalize_trans<-data.frame(t(hcc_healthy_log))
  1. Draw histogram using ggplot
#select one of the RNA (ABCB1 as example)
#use ggplot to draw histogram and modify the binwidth and colour
rawgraph<-ggplot(raw_trans,aes(x=ABCB1))+geom_histogram(binwidth=0.5,fill="deepskyblue")
normalizegraph<-ggplot(normalize_trans,aes(x=ABCB1))+geom_histogram(binwidth=0.5,fill="deepskyblue")
  1. Place the histogram side by side for better comparison
ggarrange(rawgraph,normalizegraph,ncol=2,nrow=1,labels=c("raw","normalize"))

Useful resources to explore further

Save the R codes and environment - for next section!


Additional information that may be useful in data wrangling

Data frame -> tibble in Tidyverse package

tibble() does much less than data.frame(): it never changes the type of the inputs (e.g. it never converts strings to factors!), it never changes the names of variables, it only recycles inputs of length 1, and it never creates row.names()

Reference: https://tibble.tidyverse.org/#:~:text=Tibbles%20are%20data.,a%20variable%20does%20not%20exist)..){.uri}..){.uri})

  1. Load tidyverse package
library(tidyverse)
  1. Convert data frame to tibble
hcc_tbl<-as_tibble(hcc_rna)
healthy_tbl<-as_tibble(healthy_rna)
annotation_tbl<-as_tibble(annotation)

or read_csv instead of read.lim or read.csv to import data as tibble

  1. The power of pipes in tidyverse
#For example, if you want to select column then filter, normally this is what you do:
hcc_select<-select(hcc_rna, Gene.symbol, HCC004)
hcc_filter<-filter(hcc_select, HCC004>=1000)

#with pipes
hcc_tocompare<-hcc_rna%>%select(Gene.symbol, HCC004)%>%filter(HCC004>=1000)
#colnames(dataset name)<-dataset[first row,]
#dataset$column name<-as.numeric(dataset$column name)
#using pipes:
#dataset name %>% distinct (specific column name, .keep_all=TRUE)

#without using pipes:
#distinct(dataset name, specific column, .keep_all=TRUE)

The End of Part 2

LS0tDQp0aXRsZTogIkRhdGEgV3JhbmdsaW5nIG5vdGVib29rIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRoZW1lOiByZWFkYWJsZQ0KLS0tDQoNCj4gIyMjIyMjICpUaGlzIG5vdGVib29rIGlzIFBhcnQgMiBvZiAiSW50cm9kdWN0b3J5IEJpZyBEYXRhIEFuYWx5c2VzIHRvIGdhaW4gaW5zaWdodHMgaW4gUHJlY2lzaW9uIE1lZGljaW5lIiBjb3Vyc2UuKg0KDQojIyBSIHNldHVwIFx8IEluc3RhbGwgc29mdHdhcmUNCg0KLSAgIERvd25sb2FkIGFuZCBpbnN0YWxsIFIgW1w8aHR0cHM6Ly9jbG91ZC5yLXByb2plY3Qub3JnL2Jpbi93aW5kb3dzL2Jhc2UvXD5dKGh0dHBzOi8vY2xvdWQuci1wcm9qZWN0Lm9yZy9iaW4vd2luZG93cy9iYXNlLyl7LnVyaX0NCg0KLSAgIERvd25sb2FkIGFuZCBpbnN0YWxsIFJzdHVkaW8gW1w8aHR0cHM6Ly93d3cucnN0dWRpby5jb20vcHJvZHVjdHMvcnN0dWRpby9kb3dubG9hZC9cPl0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcHJvZHVjdHMvcnN0dWRpby9kb3dubG9hZC8pey51cml9DQoNCiMjIFIgc2V0dXAgXHwgUGFja2FnZXMNCg0KLSAgIEluc3RhbGwgcGFja2FnZQ0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoJ2RwbHlyJywgZGVwZW5jaWVzPVRSVUUpDQpgYGANCg0KLSAgIExvYWQgcGFja2FnZQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpgYGANCg0KIyMgRG93bmxvYWQgZGF0YSBhbmQgb3BlbiBmaWxlIGluIFINCg0KMS4gIERvd25sb2FkIGRhdGEgZnJvbSBbZXhvcmJhc2VdKGh0dHA6Ly93d3cuZXhvcmJhc2Uub3JnL2V4b1JCYXNlVjIvZG93bmxvYWQvdG9JbmRleCkgd2Vic2l0ZS4NCg0KMi4gIE9wZW4gZmlsZSBpbiBSDQoNCmBgYHtyfQ0KaGNjX3JuYTwtcmVhZC5kZWxpbShmaWxlLmNob29zZSgpLGhlYWRlcj1UUlVFKQ0KaGVhbHRoeV9ybmE8LXJlYWQuZGVsaW0oZmlsZS5jaG9vc2UoKSxoZWFkZXI9VFJVRSkNCmBgYA0KDQojIyMjIE90aGVyIGZ1bmN0aW9ucyB0byBvcGVuIGZpbGUNCg0KIVtdKEltYWdlcy9BbHRjb2Rlc3JlYWRmaWxlLmpwZyl7d2lkdGg9IjQ1OSJ9DQoNCiMjIFIgcGFja2FnZXMgZm9yIERhdGEgd3JhbmdsaW5nDQoNCi0gICBBIHR5cGljYWwgZGF0YSBzY2llbmNlIHByb2plY3QgOg0KDQohW10oSW1hZ2VzL292ZXJ2aWV3JTIwb2YlMjBkYXRhc2NpLmpwZyl7d2lkdGg9IjUzNiJ9DQoNCipSZWZlcmVuY2U6IEdyb2xlbXVuZCwgRy4sICYgV2lja2hhbSwgSC4gKDIwMTcpLiBSIGZvciBEYXRhIFNjaWVuY2UuIE8nUmVpbGx5IE1lZGlhLioNCg0KLSAgIFRvIG1hbmlwdWxhdGUgdGhlIGRhdGEgZm9yIGRhdGEgdmlzdWFsaXphdGlvbi9pbnNpZ2h0cywgd2UgY2FuIHVzZSAiZHBseXIiIG9yICJ0aWR5dmVyc2UiIHBhY2thZ2UgaW4gUi4NCg0KICAgIDEuICBkcGx5cg0KDQogICAgICAgICFbXShJbWFnZXMvZHBseXIuanBnKXt3aWR0aD0iMzQwIn0NCg0KICAgICAgICAqUmVmZXJlbmNlOiA8aHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnLz4qDQoNCiAgICAyLiAgVGlkeXZlcnNlIC0gY29sbGVjdGlvbiBvZiBSIHBhY2thZ2VzIGZvciBkYXRhIHNjaWVuY2UNCg0KICAgICAgICAoZHBseXIgaXMgb25lIG9mIHRoZSBjb3JlIHBhY2thZ2VzIGluIHRpZHl2ZXJzZSkNCg0KICAgICAgICAhW10oSW1hZ2VzL3RpZHl2ZXJzZSUyMHBhY2thZ2UuanBnKXt3aWR0aD0iMzgwIn0NCg0KICAgICAgICAqUmVmZXJlbmNlOiA8aHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8+Kg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgU3RlcCAxIERhdGEgd3JhbmdsaW5nIHVzaW5nIGRwbHlyIHBhY2thZ2VzDQoNCiMjIyMgMS4gTG9hZCBkcGx5ciBwYWNrYWdlDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmBgYA0KDQojIyMjIDIuIEZpbHRlciByb3dzDQoNCmBgYHtyfQ0KIyBmaWx0ZXIgKCBkYXRhIGZyYW1lLCBjb2x1bW4gbmFtZSA9PSB2YWx1ZSkgDQojIGNhbiB1c2UgPCwgPD0sID4sID49DQpGR1JfZXhwcmVzc2lvbjwtZmlsdGVyKGhjY19ybmEsIEdlbmUuc3ltYm9sPT0iRkdSIikNCmhjYzAwNF9leHByZXNzaW9uPC1maWx0ZXIoaGNjX3JuYSwgSENDMDA0PD0xKQ0KDQojaWYgeW91IGhhdmUgbXVsdGlwbGUgY3JpdGVyaWENCiMgY2FuIHVzZSB8IChvciksICYgKGFuZCkNCmhjYzAwNF9oY2MwMDJfZXhwcmVzc2lvbjwtZmlsdGVyKGhjY19ybmEsIEhDQzAwNDw9MSAmIEhDQzAwMj4xKQ0KYGBgDQoNCiFbXShJbWFnZXMvZmlsdGVyJTIwY29kZXMuanBnKXt3aWR0aD0iNDE2In0NCg0KKlJlZmVyZW5jZToqIFsqaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDIvZGF0YS13cmFuZ2xpbmctY2hlYXRzaGVldC5wZGYqXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMi9kYXRhLXdyYW5nbGluZy1jaGVhdHNoZWV0LnBkZikNCg0KIyMjIyAzLiBBcnJhbmdlIHJvd3MNCg0KYGBge3J9DQojIGFycmFuZ2UgKGRhdGEgZnJhbWUsIGNvbHVtbiBuYW1lKQ0KaGNjX3NvcnQ8LWFycmFuZ2UoaGNjX3JuYSwgR2VuZS5zeW1ib2wpDQoNCiNzb3J0IGJ5IG1vcmUgdGhhbiBvbmUgdmFyaWFibGUNCmhjY19zb3J0PC1hcnJhbmdlKGhjY19ybmEsIEhDQzAwMSxHZW5lLnN5bWJvbCkNCmBgYA0KDQojIyMjIDQuIFNlbGVjdCBjb2x1bW5zDQoNCmBgYHtyfQ0KIyBzZWxlY3QgKGRhdGEgZnJhbWUsIGNvbHVtbiBuYW1lIDEsIGNvbHVtbiBuYW1lIDIpDQpoY2Nfc2VsZWN0PC1zZWxlY3QoaGNjX3JuYSwgR2VuZS5zeW1ib2wsIEhDQzAwNCkNCmBgYA0KDQojIyMjIDUuIFNlbGVjdCBhbGwgY29sdW1ucyBleGNlcHQgc3BlY2lmaWMgY29sdW1uDQoNCmBgYHtyfQ0KIyBzZWxlY3QgKGRhdGEgZnJhbWUsIC1jb2x1bW5zIHRoYXQgeW91IGRvbid0IHdhbnQpDQpoY2NfYWxsPC1zZWxlY3QoaGNjX3JuYSwgLWMoR2VuZS5zeW1ib2wsIEhDQzAwNCkpDQpgYGANCg0KIyMjIyA2LiBSZWNvZGUgZGF0YQ0KDQojIyMjIyMgZWcuIENhbGN1bGF0ZSBob3cgbWFueSBwYXRpZW50cyB0aGF0IGhhdmUgUk5BIGV4cHJlc3Npb24gXD4wIGFuZCBzdG9yZSB0aGlzIHZhbHVlIGluIGEgbmV3IGNvbHVtbiBjYWxsZWQgImNvdW50aGlnaGV4cCINCg0KYGBge3J9DQojIG11dGF0ZSAoZGF0YSBmcmFtZSwgbmV3IGNvbHVtbiBuYW1lID0gZnVuY3Rpb25zKQ0KaGNjX2hpZ2hleHA8LW11dGF0ZShoY2Nfcm5hLGNvdW50aGlnaGV4cD1yb3dTdW1zKGhjY19ybmE+MCkpDQpgYGANCg0KIyMjIyMjIGVnLiBSZWNvZGUgbnVtZXJpYyB2YWx1ZXMgdG8gY2F0ZWdvcmllcw0KDQpgYGB7cn0NCiMgbXV0YXRlIChkYXRhIGZyYW1lLCBuZXcgY29sdW1uIG5hbWUgPSBmdW5jdGlvbnMpDQpoY2NfaGlnaGV4cCA8LW11dGF0ZShoY2NfaGlnaGV4cCwgY2F0ID0gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50aGlnaGV4cCA8IDUwIH4gImxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgY291bnRoaWdoZXhwID49IDUwIH4gImhpZ2giKSkNCmBgYA0KDQojIyMjIDcuIFN1bW1hcml6ZSBkYXRhDQoNCmBgYHtyfQ0Kc3VtbWFyaXplKGhjY19oaWdoZXhwLG1lYW4oY291bnRoaWdoZXhwKSkNCmBgYA0KDQojIyMjIDguIEhhbmRsZSByZWxhdGlvbmFsIGRhdGEgKE11bHRpcGxlIHRhYmxlcyBvZiBkYXRhKQ0KDQohW10oSW1hZ2VzL3VuZGVyc3RhbmQlMjBqb2luLmpwZyl7d2lkdGg9IjE0OCJ9DQoNCiFbXShJbWFnZXMvSW5uZXJqb2luLmpwZyl7d2lkdGg9IjI0NSJ9DQoNCiFbXShJbWFnZXMvT3V0ZXJqb2luLmpwZyl7d2lkdGg9IjI5NSJ9DQoNCiFbXShJbWFnZXMvRmlsdGVyaW5nJTIwam9pbi5qcGcpe3dpZHRoPSIzNDgifQ0KDQoqUmVmZXJlbmNlOiBHcm9sZW11bmQsIEcuLCAmIFdpY2toYW0sIEguICgyMDE3KS4gUiBmb3IgRGF0YSBTY2llbmNlLiBPJ1JlaWxseSBNZWRpYS4qDQoNCmBgYHtyfQ0KIyBpbm5lcl9qb2luIChkYXRhIGZyYW1lIDEsIGRhdGEgZnJhbWUgMiwgYnk9ImtleSIpDQpoY2NfaGVhbHRoeTwtaW5uZXJfam9pbihoY2Nfcm5hLGhlYWx0aHlfcm5hLCBieT0iR2VuZS5zeW1ib2wiKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgRXhlcmNpc2UgMQ0KDQoxLiAgR2VuZXJhdGUgYSBtYXN0ZXJzaGVldCBieSBtZXJnaW5nICoqaGNjX3JuYSoqIGRhdGFzZXQgYW5kICoqaGVhbHRoeV9ybmEqKiBkYXRhc2V0LiBOYW1lIHRoZSBuZXcgbWFzdGVyc2hlZXQgYXMgKipoY2NfaGVhbHRoeSoqLg0KDQogICAgIyMjIyMjICpRdWVzdGlvbjogV2hhdCB0eXBlIG9mIGpvaW4gd2lsbCB5b3UgdXNlIGZvciB0aGlzIGRhdGFzZXQ/Kg0KDQoyLiAgU3VtbWFyaXplIG51bWJlciBvZiBnZW5lcyBmcm9tICoqaGNjX2hlYWx0aHkqKi4NCg0KMy4gIEluICoqaGNjX2hlYWx0aHkqKiwgdXNlIEdlbmUuc3ltYm9sIGNvbHVtbiBhcyByb3cgbmFtZXMgb2YgdGhlIHRhYmxlLg0KDQpgYGB7cn0NCiN3aXRob3V0IGFueSBwYWNrYWdlOiBkYXRhLmZyYW1lKGRhdGFzZXQgbmFtZSwgcm93Lm5hbWVzID0gY29sdW1uIG51bWJlcikNCiN1c2luZyB0aWR5dmVyc2UgcGFja2FnZTogY29sdW1uX3RvX3Jvd25hbWVzKGRhdGFzZXQgbmFtZSAsIHZhcj0ia2V5IikgDQpgYGANCg0KNC4gIFRoZW4sIHJlbW92ZSBnZW5lcyB0aGF0IGhhdmUgMCBleHByZXNzaW9uIGluIDkwJSBvZiBzYW1wbGVzIGluIHRoZSBkYXRhc2V0LiBOYW1lIHRoZSBkYXRhc2V0IGFzICoqaGNjX2hlYWx0aHlfaGlnaGV4cCoqDQo1LiAgU3VtbWFyaXplIHRoZSBudW1iZXIgb2YgZ2VuZXMgdGhhdCBoYXZlIGV4cHJlc3Npb24gdmFsdWUgXD4wIGluIDkwJSBvZiB0aGUgc2FtcGxlcy4NCjYuICBOb3JtYWxpemUgYWxsIGdlbmUgZXhwcmVzc2lvbnMgdXNpbmcgdGhlIGxvZzIgdHJhbnNmb3JtYXRpb24uIE5hbWUgdGhlIGRhdGFzZXQgYXMgKipoY2NfaGVhbHRoeV9sb2cqKg0KDQpgYGB7cn0NCiNsb2coKGRhdGEgZnJhbWUrMSksMikNCmBgYA0KDQojIyMjIEV4ZXJjaXNlIDEgYW5zd2Vycw0KDQpgYGB7cn0NCiNtZXJnZSBoY2Nfcm5hIHdpdGggaGVhbHRoeV9ybmENCmhjY19oZWFsdGh5PC1mdWxsX2pvaW4oaGNjX3JuYSxoZWFsdGh5X3JuYSkNCiMzNTUxNyBnZW5lcw0KDQojY29udmVydCBnZW5lIHN5bWJvbCBjb2x1bW4gdG8gcm93bmFtZXMNCmhjY19oZWFsdGh5IDwtIGRhdGEuZnJhbWUoaGNjX2hlYWx0aHksIHJvdy5uYW1lcyA9IDEpDQoNCiNyZW1vdmUgZ2VuZXMgdGhhdCBoYXMgMCBleHByZXNzaW9uIGluIDkwJSBvZiBzYW1wbGVzIGluIGJvdGggZGF0YXNldHMNCmhjY19oZWFsdGh5PC1tdXRhdGUoaGNjX2hlYWx0aHksY291bnQwPXJvd1N1bXMoaGNjX2hlYWx0aHk8PTApKQ0KaGNjX2hlYWx0aHlfaGlnaGV4cDwtZmlsdGVyKGhjY19oZWFsdGh5LGNvdW50MDw9MjA3KQ0KaGNjX2hlYWx0aHlfaGlnaGV4cDwtc2VsZWN0KGhjY19oZWFsdGh5X2hpZ2hleHAsLWNvdW50MCkNCiMxOCw1NzUgZ2VuZXMgbGVmdA0KDQojbG9nIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBkYXRhDQpoY2NfaGVhbHRoeV9sb2c8LWxvZygoaGNjX2hlYWx0aHlfaGlnaGV4cCsxKSwyKQ0KYGBgDQoNCiMjIEFib3V0IERhdGEgbm9ybWFsaXphdGlvbg0KDQotICAgTG9nIHRyYW5zZm9ybWF0aW9uIC0gdG8gbW9kZXJhdGUgdGhlIHZhcmlhbmNlIGFjcm9zcyB0aGUgbWVhbg0KDQohW10oSW1hZ2VzL0RhdGElMjBub3JtYWxpemF0aW9uLmpwZyl7d2lkdGg9IjYxNiJ9DQoNCi0gICBSZWFzb24gdG8gdXNlIExvZzIgaW5zdGVhZCBvZiBMb2cxMA0KDQohW10oSW1hZ2VzL2xvZzJyZWFzb24uanBnKXt3aWR0aD0iNjE0In0NCg0KLSAgIFJlYXNvbiBmb3IgZXhwcmVzc2lvbiB2YWx1ZSArIDEgYmVmb3JlIGxvZyB0cmFuc2Zvcm1hdGlvbg0KDQohW10oSW1hZ2VzL0RhdGElMjBub3JtYWxpemF0aW9uMi5qcGcpe3dpZHRoPSI2MTgifQ0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgU3RlcCAzYSBEYXRhIHZpc3VhbGl6YXRpb24gKEJhc2ljIGhpc3RvZ3JhbSkNCg0KIyMjIFIgcGFja2FnZXMgZm9yIGRhdGEgdmlzdWFsaXphdGlvbnMNCg0KYGBge3J9DQojSW5zdGFsbCBwYWNrYWdlcw0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIsZGVwZW5kZW5jaWVzPVRSVUUpDQppbnN0YWxsLnBhY2thZ2VzKCJnZ3B1YnIiLGRlcGVuZGVuY2llcz1UUlVFKQ0KDQojTG9hZCBwYWNrYWdlcw0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ3B1YnIpDQpgYGANCg0KIVtdKEltYWdlcy9HR3Bsb3QyLmpwZykNCg0KKlJlZmVyZW5jZToqIFsqaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9jaGVhdHNoZWV0cy9kYXRhLXZpc3VhbGl6YXRpb24ucGRmKl0oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9jaGVhdHNoZWV0cy9kYXRhLXZpc3VhbGl6YXRpb24ucGRmKQ0KDQpMZXQncyB2aXN1YWxpemUgdGhlIHRoZSBkYXRhc2V0IGJlZm9yZSBhbmQgYWZ0ZXIgbm9ybWFsaXphdGlvbg0KDQoxLiAgVHJhbnNwb3NlIHRoZSBkYXRhc2V0DQoNCmBgYHtyfQ0KI1RyYW5zcG9zZSB0aGUgZGF0YXNldHMgc28gdGhhdCB0aGUgUk5BIG5hbWVzIGFyZSBpbiBjb2x1bW5zIHdoaWxlIHNhbXBsZXMgYXJlIGluIHJvd3MNCnJhd190cmFuczwtZGF0YS5mcmFtZSh0KGhjY19oZWFsdGh5KSkNCm5vcm1hbGl6ZV90cmFuczwtZGF0YS5mcmFtZSh0KGhjY19oZWFsdGh5X2xvZykpDQpgYGANCg0KMi4gIERyYXcgaGlzdG9ncmFtIHVzaW5nIGdncGxvdA0KDQpgYGB7cn0NCiNzZWxlY3Qgb25lIG9mIHRoZSBSTkEgKEFCQ0IxIGFzIGV4YW1wbGUpDQojdXNlIGdncGxvdCB0byBkcmF3IGhpc3RvZ3JhbSBhbmQgbW9kaWZ5IHRoZSBiaW53aWR0aCBhbmQgY29sb3VyDQpyYXdncmFwaDwtZ2dwbG90KHJhd190cmFucyxhZXMoeD1BQkNCMSkpK2dlb21faGlzdG9ncmFtKGJpbndpZHRoPTAuNSxmaWxsPSJkZWVwc2t5Ymx1ZSIpDQpub3JtYWxpemVncmFwaDwtZ2dwbG90KG5vcm1hbGl6ZV90cmFucyxhZXMoeD1BQkNCMSkpK2dlb21faGlzdG9ncmFtKGJpbndpZHRoPTAuNSxmaWxsPSJkZWVwc2t5Ymx1ZSIpDQpgYGANCg0KMy4gIFBsYWNlIHRoZSBoaXN0b2dyYW0gc2lkZSBieSBzaWRlIGZvciBiZXR0ZXIgY29tcGFyaXNvbg0KDQpgYGB7cn0NCmdnYXJyYW5nZShyYXdncmFwaCxub3JtYWxpemVncmFwaCxuY29sPTIsbnJvdz0xLGxhYmVscz1jKCJyYXciLCJub3JtYWxpemUiKSkNCmBgYA0KDQojIyMgVXNlZnVsIHJlc291cmNlcyB0byBleHBsb3JlIGZ1cnRoZXINCg0KIVtdKEltYWdlcy9HR3Bsb3QyX290aGVycmVzb3VyY2VzLmpwZykNCg0KKioqU2F2ZSB0aGUgUiBjb2RlcyBhbmQgZW52aXJvbm1lbnQgLSBmb3IgbmV4dCBzZWN0aW9uISoqKg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgQWRkaXRpb25hbCBpbmZvcm1hdGlvbiB0aGF0IG1heSBiZSB1c2VmdWwgaW4gZGF0YSB3cmFuZ2xpbmcNCg0KLSAgIEludHJvZHVjdGlvbiB0byBUaWR5dmVyc2UgcGFja2FnZQ0KDQpEYXRhIGZyYW1lIC1cPiB0aWJibGUgaW4gVGlkeXZlcnNlIHBhY2thZ2UNCg0KIVtdKEltYWdlcy9UaWJibGUuanBnKXt3aWR0aD0iNDE4In0NCg0KW2B0aWJibGUoKWBdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3RpYmJsZS5odG1sKSBkb2VzIG11Y2ggbGVzcyB0aGFuIFtgZGF0YS5mcmFtZSgpYF0oaHR0cHM6Ly9yZHJyLmlvL3IvYmFzZS9kYXRhLmZyYW1lLmh0bWwpOiBpdCBuZXZlciBjaGFuZ2VzIHRoZSB0eXBlIG9mIHRoZSBpbnB1dHMgKGUuZy7CoGl0IG5ldmVyIGNvbnZlcnRzIHN0cmluZ3MgdG8gZmFjdG9ycyEpLCBpdCBuZXZlciBjaGFuZ2VzIHRoZSBuYW1lcyBvZiB2YXJpYWJsZXMsIGl0IG9ubHkgcmVjeWNsZXMgaW5wdXRzIG9mIGxlbmd0aCAxLCBhbmQgaXQgbmV2ZXIgY3JlYXRlcyBgcm93Lm5hbWVzKClgDQoNCipSZWZlcmVuY2U6IFtodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnLyM6XH46dGV4dD1UaWJibGVzJTIwYXJlJTIwZGF0YS4sYSUyMHZhcmlhYmxlJTIwZG9lcyUyMG5vdCUyMGV4aXN0KS4uKXsudXJpfV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8jOn46dGV4dD1UaWJibGVzJTIwYXJlJTIwZGF0YS4sYSUyMHZhcmlhYmxlJTIwZG9lcyUyMG5vdCUyMGV4aXN0KS4uKXsudXJpfSkqDQoNCjEuICBMb2FkIHRpZHl2ZXJzZSBwYWNrYWdlDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KMi4gIENvbnZlcnQgZGF0YSBmcmFtZSB0byB0aWJibGUNCg0KYGBge3J9DQpoY2NfdGJsPC1hc190aWJibGUoaGNjX3JuYSkNCmhlYWx0aHlfdGJsPC1hc190aWJibGUoaGVhbHRoeV9ybmEpDQphbm5vdGF0aW9uX3RibDwtYXNfdGliYmxlKGFubm90YXRpb24pDQpgYGANCg0Kb3IgKipyZWFkX2NzdioqIGluc3RlYWQgb2YgKipyZWFkLmxpbSoqIG9yICoqcmVhZC5jc3YqKiB0byBpbXBvcnQgZGF0YSBhcyB0aWJibGUNCg0KMy4gIFRoZSBwb3dlciBvZiBwaXBlcyBpbiB0aWR5dmVyc2UNCg0KYGBge3J9DQojRm9yIGV4YW1wbGUsIGlmIHlvdSB3YW50IHRvIHNlbGVjdCBjb2x1bW4gdGhlbiBmaWx0ZXIsIG5vcm1hbGx5IHRoaXMgaXMgd2hhdCB5b3UgZG86DQpoY2Nfc2VsZWN0PC1zZWxlY3QoaGNjX3JuYSwgR2VuZS5zeW1ib2wsIEhDQzAwNCkNCmhjY19maWx0ZXI8LWZpbHRlcihoY2Nfc2VsZWN0LCBIQ0MwMDQ+PTEwMDApDQoNCiN3aXRoIHBpcGVzDQpoY2NfdG9jb21wYXJlPC1oY2Nfcm5hJT4lc2VsZWN0KEdlbmUuc3ltYm9sLCBIQ0MwMDQpJT4lZmlsdGVyKEhDQzAwND49MTAwMCkNCmBgYA0KDQotICAgVG8gc3BlY2lmeSBjb2x1bW4gbmFtZXMNCg0KYGBge3J9DQojY29sbmFtZXMoZGF0YXNldCBuYW1lKTwtZGF0YXNldFtmaXJzdCByb3csXQ0KYGBgDQoNCi0gICBUbyBjaGFuZ2UgZGF0YSB0eXBlIG9mIGEgY29sdW1uIChlZy4gY2hhcmFjdGVyIHRvIG51bWVyaWMpDQoNCmBgYHtyfQ0KI2RhdGFzZXQkY29sdW1uIG5hbWU8LWFzLm51bWVyaWMoZGF0YXNldCRjb2x1bW4gbmFtZSkNCmBgYA0KDQotICAgVG8gcmVtb3ZlIGR1cGxpY2F0ZXMNCg0KYGBge3J9DQojdXNpbmcgcGlwZXM6DQojZGF0YXNldCBuYW1lICU+JSBkaXN0aW5jdCAoc3BlY2lmaWMgY29sdW1uIG5hbWUsIC5rZWVwX2FsbD1UUlVFKQ0KDQojd2l0aG91dCB1c2luZyBwaXBlczoNCiNkaXN0aW5jdChkYXRhc2V0IG5hbWUsIHNwZWNpZmljIGNvbHVtbiwgLmtlZXBfYWxsPVRSVUUpDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClRoZSBFbmQgb2YgUGFydCAyDQo=